<?php
include_once('sphinxapi.php');
//学生社区资讯
define("DEFINE_SEARCH_TYPE_COMMUNITY_NEWS", 3);
//学生社区博客
define("DEFINE_SEARCH_TYPE_COMMUNITY_BLOG", 4);
//学生社区论坛
define("DEFINE_SEARCH_TYPE_COMMUNITY_BBS", 5);
class searcher
{
	private $sphinxer;
	/**
	 * 索引名称
	 *
	 * @var string
	 */
	private $indexer;
	/**
	 * 错误信息
	 *
	 * @var string
	 */
	private $error_msg;
	/**
	 * 来源过滤
	 */
	private $source;
	
	/**
	 * 数据库连接配置
	 *
	 * @var unknown_type
	 */
	private $db_conf = array(
								"host"		=>"192.168.0.9",
								"port"		=>"3306",
								"username"	=>"root",
								"password"	=>"edufe",
								"dbname"	=>"test_sphinx"
							);
	/**
	 * 数据库连接句柄
	 *
	 * @var unknown_type
	 */
	private $db_conn;
	
	/**
	 * 摘要配置
	 *
	 * @var array
	 */
	public $opts = array(
						        "before_match"          		=> "<b><font color='red'>",  //关键字前的字符串
						        "after_match"           		=> "</font></b>",    //关键字后的字符串
						        "chunk_separator"       		=> "",				//摘要之间的字符串
						        "exact_phrase"					=> 0,				//是否高亮
						        "around"                        => 11,				//关键字前后的字符数
						        "limit"							=> 256,				//摘要最多包含的符号数
						        "single_passage"				=> 1,				//是否只摘要最匹配的一段话
						);
	
	/**
	 * 构造函数
	 *
	 * @param string $host  
	 * @param int $port
	 * @param string $indexer
	 */
	function __construct($host, $port, $indexer)
	{
		$this->sphinxer = new SphinxClient();
		$this->sphinxer->SetServer($host, intval($port));
		$this->sphinxer->SetMatchMode(SPH_MATCH_EXTENDED2);
		$this->sphinxer->SetFieldWeights(array('title'=>100000, 'content'=>1));
		$this->sphinxer->SetSortMode(SPH_SORT_RELEVANCE);
		$this->sphinxer->SetRankingMode(SPH_RANK_PROXIMITY_BM25);
		$this->indexer = $indexer;
	}
	
	/**
	 * 设置结果集范围
	 *
	 * @param int $start
	 * @param int $limit
	 */
	function set_limit($start, $limit)
	{
		$start = intval($start);
		$limit = intval($limit);
		$this->sphinxer->SetLimits ($start, $limit, ( $limit > 10000 ) ? $limit : 10000 );
	}
	
	/**
	 * 设置来源
	 *
	 * @param unknown_type $value
	 */
	function set_source($value)
	{
		if(is_numeric($value))
		{
			$this->source[] = $value;
		}
		else 
		{
			$this->error_msg = 'source must number';
			return false;
		}
	}
	
	/**
	 * 查询结果
	 *
	 * @param string $string  要查询的字符串
 	 * @return unknown
	 */
	function search($string, $only_id=false)
	{
		if(!empty($this->error_msg))
		{
			return false;
		}
		$string_array = explode(" ", $string);
		foreach ($string_array as $k=>$v)
		{
			if(trim($v) == '')
			{
				unset($string_array[$k]);
			}
		}
		$_string = "(" . implode(")|(", $string_array) . ")";
		if(is_array($this->source) && sizeof($this->source) >0 )
		{
			$this->sphinxer->SetFilter('source', $this->source);
		}
		$res = $this->sphinxer->Query($_string, $this->indexer);
		if($res === false)
		{
			$this->error_msg = $this->sphinxer->GetLastError();
			return false;
		}
		if($res['total_found'] == '0')
		{
			$art_list = array();
		}
		else 
		{
			$id_list = array_keys($res['matches']);
			if($only_id === false)
			{
				$art_list = $this->get_art_list($id_list, $string);
			}
			else 
			{
				$art_list = $id_list;
			}
		}
		$result = array("total_found"=>$res['total_found'] > 10000 ? 10000 : $res['total_found'], "time"=>$res['time'], "list"=>$art_list);
		return $result;
	}
	
	/**
	 * 删除一条记录
	 *
	 * @param unknown_type $source
	 * @param unknown_type $id
	 * @return unknown
	 */
	function delete($source, $id)
	{
		if($this->db_connect() === false)
		{
			return false;
		}
		$sql = sprintf("update search_article set status=0 where source=%d and fid='%s'", $source, $id);
		$res = $this->db_query($sql);
		$this->db_close();
		return $res;
	}
	
	/**
	 * 修改一条记录
	 *
	 * @param unknown_type $title
	 * @param unknown_type $content
	 * @param unknown_type $source
	 * @param unknown_type $id
	 * @return unknown
	 */
	function update($title, $content, $source, $id)
	{
		if($this->db_connect() === false)
		{
			return false;
		}
		$sql = sprintf("update search_article set title='%s',content='%s' where source=%d and fid='%s'",
						mysql_escape_string($title),
						mysql_escape_string($content),
						$source, $id);
		$res = $this->db_query($sql);
		$this->db_close();
		return $res;
	}
	
	/**
	 * 根据id获得搜索内容以及摘要
	 *
	 * @param array $id_list  id列表
	 * @param string $string  要搜索的字符串
	 * @return unknown
	 */
	private function get_art_list($id_list, $string)
	{
		if($this->db_connect() === false)
		{
			return false;
		}
		$sql = "select * from search_article where id in (" . implode(",", $id_list) . ")";
		$res = $this->db_select($sql);
		if($res === false)
		{
			$this->db_close();
			return false;
		}
		$this->db_close();
		$list = array();
		foreach ($res as $k=>$v)
		{
			$list[$k] = strip_tags($v['content'], '<br>');
		}
		$_list = $this->sphinxer->BuildExcerpts ($list, $this->indexer, $string, $this->opts);
		foreach ($res  as $k=>$v)
		{
			$res[$k]['content'] = $_list[$k];
		}
		return $res;
	}
	
	/**
	 * 连接数据库
	 *
	 * @return unknown
	 */
	private function db_connect()
	{
		$this->db_conn = mysql_connect($this->db_conf['host'] . ":" .$this->db_conf['port'], $this->db_conf['username'], $this->db_conf['password'], true);
		if($this->db_conn === false)
		{
			$this->error_msg = "can not connect search db";
			return false;
		}
		if(!mysql_select_db($this->db_conf['dbname'], $this->db_conn))
		{
			$this->error_msg = "can not open search db";
			return false;
		}
		mysql_query('set names \'utf8\'', $this->db_conn);
		return true;
	}
	
	/**
	 * 查询数据库
	 *
	 * @param unknown_type $sql
	 * @return unknown
	 */
	private function db_select($sql)
	{
		$res = $this->db_query($sql);
		if($res === false)
		{
			return false;
		}
		$list = array();
		while($row = mysql_fetch_array($res, MYSQL_ASSOC))
		{
			$list[] = $row;
		}
		return $list;
	}
	
	/**
	 * 执行sql语句
	 *
	 * @param unknown_type $sql
	 * @return unknown
	 */
	private function db_query($sql)
	{
		$res = mysql_query($sql, $this->db_conn);
		if($res === false)
		{
			$this->error_msg = mysql_error($this->db_conn);
			return false;
		}
		return $res;
	}
	
	/**
	 * 关闭数据库连接
	 *
	 */
	private function db_close()
	{
		mysql_close($this->db_conn);
	}
	
	/**
	 * 获取错误信息
	 *
	 * @return unknown
	 */
	function get_error()
	{
		return $this->error_msg;
	}
}
?>